package com.leyou.search.service.impl;

import com.leyou.common.dto.PageDTO;
import com.leyou.common.exception.LyException;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.item.dto.SpecParamDTO;
import com.leyou.item.dto.SpuDTO;
import com.leyou.search.Repository.GoodsRepository;
import com.leyou.search.dto.SearchParamDTO;
import com.leyou.search.entity.Goods;
import com.leyou.search.service.SearchService;


import com.leyou.starter.elastic.dto.PageInfo;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;


import java.util.*;
import java.util.stream.Collectors;

import static com.leyou.search.constants.SearchConstants.*;

@Service
@Slf4j
public class SearchServiceImpl implements SearchService {

    private final GoodsRepository goodsRepository;

    private final ItemClient itemClient;

    public SearchServiceImpl(GoodsRepository goodsRepository, ItemClient itemClient) {
        this.goodsRepository = goodsRepository;
        this.itemClient = itemClient;
    }

    @Override
    public void createIndexAndMapping() {
        try {
            //先删除已存在的索引库
            goodsRepository.deleteIndex();
        } catch (Exception e) {
           log.info("删除失败，可能索引库不存在！");
        }
        //创建一个索引库
        goodsRepository.createIndex(INDEX_SOURCE);
        log.info("索引库创建完成");
    }


    @Override
    public void loadData() {
        int page=1;
        int rows=40;
    while (true){
        log.info("开始导入第{}页数据", page);
        //查询spu
        PageDTO<SpuDTO> spuDTOPageDTO = itemClient.querySpuByPage(page, rows, true, null, null, null);
        List<SpuDTO> items = spuDTOPageDTO.getItems();
        List<Goods> goodsList=new ArrayList<>();
        for (SpuDTO item : items) {
            Goods goods= buildGoods(item);
            goodsList.add(goods);
        }
//        List<Goods> goodsList = items.stream().map(this::buildGoods).collect(Collectors.toList());
        //转换
        goodsRepository.saveAll(goodsList);
        log.info("导入第{}页数据结束。", page);
        //翻页
        page++;
        if (page>spuDTOPageDTO.getTotalPage()){
            //当页数达到最大停止
            break;
        }
    }

    }

    @Override
    public Mono<List<String>> getSuggestion(String key) {
        //先健壮性判断参数
        if (StringUtils.isBlank(key)){
            throw new LyException(400,"参数不能为空");
        }
        return goodsRepository.suggestBySingleField(SUGGESTION_FIELD,key);
    }

    @Override
    public void saveGoodsById(Long spuId) {
        SpuDTO spuDTO = itemClient.queryGoodsById(spuId);
        Goods goods = buildGoods(spuDTO);
        goodsRepository.save(goods);
    }

    @Override
    public void deleteGoodsById(Long spuId) {
        goodsRepository.deleteById(spuId);
    }

    @Override
    public Mono<PageInfo<Goods>> searchGoods(SearchParamDTO req) {
        //由于参数都是数据 需要封装到请求中
        //1创建工厂对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //使用对象封装请求
        //2.1先过滤
        searchSourceBuilder.fetchSource(DEFAULT_SOURCE_FIELD ,new String[0]);
        //查询条件封装
        String key = req.getKey();
        //健壮性判断
        if (StringUtils.isBlank(key)){
            throw new LyException(400,"搜索条件不能为空");
        }
        searchSourceBuilder.query(QueryBuilders.matchQuery(DEFAULT_SEARCH_FIELD,key));
        //分页
        searchSourceBuilder.from(req.getFrom());
        searchSourceBuilder.size(req.getSize());
        //排序
        String sortBy = req.getSortBy();
        if (StringUtils.isNotBlank(sortBy)){
            searchSourceBuilder.sort(sortBy,req.getDesc()?SortOrder.DESC:SortOrder.ASC);
        }
        //高亮
        searchSourceBuilder.highlighter(new HighlightBuilder().field(DEFAULT_SEARCH_FIELD).preTags(DEFAULT_PRE_TAG).postTags(DEFAULT_POST_TAG));
        return goodsRepository.queryBySourceBuilderForPageHighlight(searchSourceBuilder);
    }

    private Goods buildGoods(SpuDTO item) {
    //自动补全的字段
        ArrayList<String> strings = new ArrayList<>(Arrays.asList(StringUtils.split(item.getCategoryName(), "/")));
        strings.add(item.getName());
        strings.add(item.getBrandName());

        List<SkuDTO> skus = item.getSkus();
        if (skus==null){
            skus=itemClient.querySkuBySpuId(item.getId());
        }
        //价格集合
        Set<Long> price = skus.stream().map(SkuDTO::getPrice).collect(Collectors.toSet());
        //销量
        long sold = skus.stream().mapToLong(SkuDTO::getSold).sum();
        //图片地址
        String image = StringUtils.substringBefore(skus.get(0).getImages(), ",");
        //规格参数
        ArrayList<Map<String,Object>> objects = new ArrayList<>();
        // 查询规格参数name和value键值对，只查询参与搜索的
        List<SpecParamDTO> list = itemClient.querySpecsValues(item.getId(), true);
        for (SpecParamDTO specParamDTO : list) {
            HashMap<String, Object> map = new HashMap<>();
            map.put("name",specParamDTO.getName());
            map.put("value",chooseSegment(specParamDTO));
            objects.add(map);
        }
        //创建good对象
        Goods goods = new Goods();
        goods.setUpdateTime(new Date());
        // 自动补全的提示字段
        goods.setSuggestion(strings);
        // 规格参数
        goods.setSpecs(objects);
        // 商品销量
        goods.setSold(sold);
        // 商品标题
        goods.setTitle(item.getTitle() + StringUtils.join(strings, " "));
        // sku的价格集合
        goods.setPrices(price);
        // sku的某个图片
        goods.setImage(image);
        goods.setCategoryId(item.getCid3());
        goods.setBrandId(item.getBrandId());
        goods.setId(item.getId());
        return goods;
    }

    private Object chooseSegment(SpecParamDTO p) {
        Object value = p.getValue();
        if (value==null || StringUtils.isBlank(value.toString())){
            return "其他";
        }
        if (!p.getNumeric() || StringUtils.isBlank(p.getSegments()) || value instanceof Collection){
            return value;
        }
        double val = parseDouble(value.toString());
        String result="其他";
        for (String segment: p.getSegments().split(",")){
            String[] segs = segment.split("-");
            //获取数值范围
            double begin = parseDouble(segs[0]);
            double end = Double.MAX_VALUE;
            if (segs.length==2){
                end=parseDouble(segs[1]);
            }
            //判断是否在区间
            if(val>=begin&&val<end){
                if (segs.length==1){
                    result=segs[0]+p.getUnit()+"以上";
                }
                else if (begin==0){
                    result=segs[1]+p.getUnit()+"以下";
                }
                else{
                    result=segment+p.getUnit();
                }
                break;
            }
        }
        return result;
    }

    private double parseDouble(String s) {
        try {
            return Double.parseDouble(s);
        } catch (NumberFormatException e) {
            return 0;
        }
    }
}
